const Page = require("../models/pages");
const AllFilters = require("../models/filters");
const Components = require("../models/components");
const fse = require("fs-extra");
const path = require("path");
const shell = require("shelljs");
const { del } = require("request");
// 获取相同数组
const getCommonArray = (arr1, arr2) => {
  return arr1.filter((item) => arr2.includes(item));
};

async function delp(comms, callback) {
  if (comms.length === 0) {
    return;
  }

  const comm = comms[0];
  await callback(comm);

  // 递归调用 dep 处理剩余的 comms
  await delp(comms.slice(1), callback);
}

const dep = async (comm, fun) => {
  if (!Array.isArray(comm) || comm.length === 0) {
    return;
  }
  const promises = comm.map(async (a) => {
    try {
      await fun(a);

      if (a.children && Array.isArray(a.children) && a.children.length > 0) {
        await dep(a.children, fun);
      }
    } catch (error) {
      console.error(`Error processing item ${JSON.stringify(a)}:`, error);
      throw error; // 根据需求决定是否重新抛出错误
    }
  });

  return await Promise.all(promises);
};
// 删除多余的组件
const deleteComponents = (_Page, projectCode, coms) => {
  return new Promise(async (resolve) => {
    if (_Page.components) {
      let arr = coms.map((a) => a.componentKey);
      arr = Array.from(new Set(arr));
      let brr = _Page.components.map((a) => a.componentKey);
      brr = Array.from(new Set(brr));

      const comm = getCommonArray(arr, brr);

      const RM = brr.filter((item) => !comm.includes(item));
      const dep = () => {
        const k = RM.shift();
        const src = path.resolve(
          __dirname,
          "../../projects/" + projectCode + "/src/components/" + k
        );
        if (fse.pathExistsSync(src)) {
          fse.removeSync(src);
        }
        if (RM.length > 1) {
          dep();
        } else {
          resolve();
        }
      };

      if (RM && RM.length) {
        // 判断是否有需要删除的组件
        dep();
      } else {
        resolve();
      }
    } else {
      resolve();
    }
  });
};

// 删除多余的apis
const deleteApis = (_Page, projectCode, coms) => {
  return new Promise(async (resolve) => {
    let arr = coms.map((a) => a && a.apiUrl);
    if (arr) {
      arr = arr.filter((a) => a && a.apiUrl !== "");
      arr = Array.from(new Set(arr));

      let brr = _Page.components
        .map((a) => a?.apiUrl)
        .filter((a) => a?.apiUrl !== "");
      brr = Array.from(new Set(brr));
      const comm = getCommonArray(arr, brr);

      const RM = brr.filter((item) => !comm.includes(item));
      // 判断是否有需要删除的组件
      const dep = () => {
        const k = RM.shift();

        const src = path.resolve(
          __dirname,
          "../../projects/" + projectCode + "/src/apis/" + k
        );
        if (fse.pathExistsSync(src)) {
          fse.removeSync(src);
        }
        if (RM.length > 1) {
          dep();
        } else {
          resolve();
        }
      };

      if (RM && RM.length) {
        dep();
      } else {
        resolve();
      }
    }
  });
};

const joinPackagejson = (str, projectCode) => {
  // 加入到package.json
  let m = str.match(/\/\*\{Node_modules=[a-zA-Z0-9^.]+\}\*\//gim);
  if (m && m.length) {
    m = m[0].replace(/[\/*{}]/gi, "");
    m = m.split("=")[1];
    let o = {};
    m.split(",").forEach((a) => {
      let k = a.split("^");
      o[k[0]] = k[1];
    });
    const url = path.resolve(
      __dirname,
      "../../projects/" + projectCode + "/package.json"
    );

    let pakage = fse.readFileSync(url, "utf8");
    pakage = JSON.parse(pakage);

    if (
      Object.keys(o).some((a) => !Object.keys(pakage.dependencies).includes(a))
    ) {
      Object.keys(o).forEach((k) => {
        if (!Object.keys(pakage).includes(k)) {
          pakage.dependencies[k] = "^" + o[k];
        } else {
          if (pakage.dependencies[k].replace("^", "") !== "^" + o[k]) {
            pakage.dependencies[k] = "^" + o[k];
          }
        }
      });
      fse.outputFileSync(url, JSON.stringify(pakage), "utf8");
    } else {
      let needUpdate = false;
      Object.keys(o).forEach((k) => {
        if (pakage.dependencies[k].replace("^", "") !== "^" + o[k]) {
          pakage.dependencies[k] = "^" + o[k];
          needUpdate = true;
        }
      });
      if (needUpdate) {
        fse.outputFileSync(url, JSON.stringify(pakage), "utf8");
      }
    }
  }
};

const joinComponentsToProject = (str, projectCode, code) => {
  // 组件加入到项目
  return new Promise(async (resolve) => {
    const dir = path.resolve(
      __dirname,
      "../../projects/" + projectCode + "/src/components/" + code
    );
    let sr = "";
    if (!fse.pathExistsSync(dir)) {
      await fse.outputFileSync(dir + "/index.vue", str, "utf8");
    } else {
      const stat = fse.statSync(dir);
      if (stat.isDirectory()) {
        const curl = path.resolve(dir, "index.vue");
        const txt = await fse.readFileSync(curl, "utf8");
        if (txt !== str) {
          await fse.outputFileSync(curl, str, "utf8");
        }
      } else {
        const curl = path.resolve(dir, code + ".vue");
        if (!fse.pathExistsSync(curl)) {
          fse.outputFileSync(curl, str, "utf8");
        } else {
          const txt = await fse.readFileSync(curl, "utf8");
          if (txt !== str) {
            await fse.outputFileSync(curl, str, "utf8");
          }
        }
      }
    }
    resolve(str);
  });
};

// 页面加入到项目
const joinViewsToProject = (
  id,
  projectCode,
  executes,
  modals,
  strcomm,
  url,
  grids
) => {
  return new Promise(async (resolve) => {
    const _Page = await Page.findOne({ _id: id });

    let dir = path.resolve(
      __dirname,
      "../../projects/" + projectCode + "/src/views" + _Page.url
    );
    if (_Page.url !== url && fse.pathExistsSync(dir)) {
      fse.removeSync(dir);
    }
    dir = path.resolve(
      __dirname,
      "../../projects/" + projectCode + "/src/views" + url
    );
    const page = path.resolve(__dirname, "../template/pages/app.vue");
    let str = await fse.readFileSync(page, "utf8");

    let pgf = {};
    strcomm.forEach(async (a) => {
      a = a.comm;
      const s = a.index.split("-");

      let b = JSON.parse(JSON.stringify(a));
      if (s && s.length < 3) {
        const key = b.index.split("-");
        if (!pgf[key[0]]) pgf[key[0]] = [];
        b = Object.assign({}, b, b.attrs);
        const fns = executes.excuteCommApi[b.index];
        if (fns) {
          Object.keys(fns).forEach((k) => {
            b[k] = `func_replace|${fns[k]}`;
          });

          delete b.apiUrl;
        }

        pgf[key[0]] = pgf[key[0]].concat(b);
        delete b.attrs;
        delete b._esr;
      } else {
        const key = a.index.split("-");
        const r = Object.values(pgf).flat();
        const c = r.find((a) => a.index === key[0] + "-" + key[1]);
        if (c && c.children) {
          dep(c.children, (ca) => {
            const fns = executes.excuteCommApi[ca.index];
            if (fns) {
              Object.keys(fns).forEach((k) => {
                ca.attrs.options = `func_replace|${fns[k]}`;
              });
              delete ca.apiUrl;
            }
          });
        }
      }
    });

    const pgfs = JSON.stringify(pgf).replace(
      /\"Filters.list\(\\\"([a-zA-Z0-9-_]+)\\\"\)\"/gim,
      'Filters.list("$1")'
    );

    modals = JSON.stringify(modals).replace(
      /\"Filters.list\(\\\"([a-zA-Z0-9-_]+)\\\"\)\"/gim,
      'Filters.list("$1")'
    );

    str = str.replace(
      /\/\*\{\s?pageConfig\s?\}\*\//gim,
      `const pageConfig = ref(${pgfs})\n`
    );

    str = str.replaceAll(/\"func_replace\|([a-zA-Z0-9-_()]+)\"/g, "$1");

    str = str.replace(
      /\/\*\{\s?modals\s?\}\*\//gim,
      `const modals = ref(${modals})\n`
    );

    str = str.replace(/\/\*\{\s?modals_events\s?\}\*\//gim, executes.modals);

    str = str.replace(
      /\/\*\{\s?layout\s?\}\*\//gim,
      `const layout = ref(${JSON.stringify(grids)})\n`
    );
    str = str.replaceAll(
      /\/\*\{\s?apis\s?\}\*\//gim,
      `${executes.apiUrls.join("\n")}`
    );
    str = str.replaceAll(
      /\/\*\{\s?insert_apis_methods\s?\}\*\//gim,
      `${executes.methods.join("\n")}`
    );
    str = str.replaceAll(
      /\/\*\{\s?execute_apis\s?\}\*\//gim,
      `${executes.executes.join("\n")}`
    );
    str = str.replaceAll(
      /Relace__Events/gim,
      `${executes.emits.cn.join("\n")}`
    );
    str = str.replaceAll(
      /\/\*\{\s?emits_apis\s?\}\*\//gim,
      `${executes.emits.fn.join("\n")}`
    );

    if (!fse.pathExistsSync(dir)) {
      await fse.outputFileSync(dir + "/index.vue", str, "utf8");
    } else {
      const stat = fse.statSync(dir);
      if (stat.isDirectory()) {
        const curl = path.resolve(dir, "index.vue");
        const txt = await fse.readFileSync(curl, "utf8");
        if (txt !== str) {
          await fse.outputFileSync(curl, str, "utf8");
        }
      } else {
        const curl = path.resolve(dir, code + ".vue");
        if (!fse.pathExistsSync(curl)) {
          await fse.outputFileSync(curl, str, "utf8");
        } else {
          const txt = await fse.readFileSync(curl, "utf8");
          if (txt !== str) {
            await fse.outputFileSync(curl, str, "utf8");
          }
        }
      }
    }

    resolve();
  });
};

// url转驼峰
const toHump = (str) => {
  return str
    .replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) =>
      index === 0 ? letter.toLowerCase() : letter.toUpperCase()
    )
    .replace(/\s+/g, "")
    .replace(/\//g, "");
};
// 生成apis
const joinApisToProject = async (projectCode, comm) => {
  // 接口加入到项目
  return new Promise(async (resolve) => {
    if (comm.options && comm.options.indexOf("Filters") === -1)
      (comm.apiUrl = comm.options), (comm.apiType = "get");
    if (
      comm.componentKey === "table" &&
      comm.data &&
      typeof comm.data === "string"
    ) {
      comm.apiUrl = comm.data;
      if (comm.pagination && comm.pageSize) {
        comm.pagination = {
          show: true,
          pageSize: comm.pageSize,
          pageIndex: 1,
          showQuickJumper: true,
          showSizeChanger: true,
        };
        delete comm.pageSize;
      }
    }
    if (comm.apiUrl && typeof comm.apiUrl === "string") {
      const apis = comm.apiUrl.split("|");
      await dep(apis, async (apiUrl, i) => {
        apiUrl = apiUrl.split(":");
        let apiType = "get";
        if (apiUrl.length > 1) {
          apiType = apiUrl[1];
        }
        apiUrl = apiUrl[0];
        const dir = path.resolve(
          __dirname,
          "../../projects/" + projectCode + "/src/apis/" + apiUrl + ".js"
        );
        let gs = apiType === "get" ? "params" : "data";
        let prefix = comm.prefix ? `prefix: "${comm.prefix}",` : "";
        let str = "";
        let url =
          apiType === "put" || apiType === "delete"
            ? apiUrl + "/${data.id}"
            : apiUrl;
        url = "`" + url + "`";
        let http = prefix
          ? `return http({
              method: "${apiType}",
                url: ${url},
                ${gs},
                ${prefix}
              });`
          : `return http({
                method: "${apiType}",
                url: ${url},
                ${gs}
              });`;
        let fun = toHump(apiUrl);
        str = `export const ${fun} = (${gs} = {}) => {
          ${http}
        };`;
        if (!fse.pathExistsSync(dir)) {
          await fse.outputFileSync(dir, str, "utf8");
        } else {
          const txt = await fse.readFileSync(dir, "utf8");
          if (txt !== str) {
            await fse.outputFileSync(dir, str, "utf8");
          }
        }
      });
    }

    resolve();
  });
};

// 生成路由
const joinRoutersToProject = async (id, projectCode, url, name) => {
  // 接口加入到项目
  return new Promise(async (resolve) => {
    const _Page = await Page.findOne({ _id: id });
    let dir = path.resolve(
      __dirname,
      "../../projects/" + projectCode + "/src/router/constant.js"
    );

    let str = await fse.readFileSync(dir, "utf8");
    str = str
      .replace(`import { _import } from "./_import";`, "")
      .replace("export const constantRouterMap = ", "")
      .replace(/\s/g, "")
      .replaceAll(",}", "}")
      .replaceAll(",]", "]")
      .replace(/\;$/g, "");
    str = str.replace(/"?\_import\(\"?([a-zA-Z0-9-/_]+)\"?\)"?/gim, '""');
    str = str.replace(/([a-zA-Z_]+)\:/gim, '"$1":').replace(/\,\n\]/gim, "]");
    let constant = JSON.parse(str);
    if (_Page.url !== url && constant.some((a) => a.path === _Page.url)) {
      constant = constant.filter((a) => a.path !== _Page.url);
    }

    if (constant.length < 1 || constant.every((a) => a.path !== url)) {
      constant = constant.concat({
        path: `${url}`,
        name: `${name}`,
        component: `_import("${url}")`,
      });
    } else {
      const idx = constant.findIndex((a) => a.path === url);
      constant[idx] = {
        path: `${url}`,
        name: `${name}`,
        component: `_import("${url}")`,
      };
    }
    if (constant.every((a) => a.path !== "/")) {
      constant = constant.concat({
        path: "/",
        rededict: constant[0].path,
      });
    }
    constant = constant.map((a) => {
      if (a.path && a.path !== "/") {
        a.component = `_import("${a.path}")`;
      }
      return a;
    });
    constant = JSON.stringify(constant).replace(
      /\"\_import\(\\\"([a-zA-Z0-9-/_]+)\\\"\)\"/gim,
      '_import("$1")'
    );

    str = `import { _import } from "./_import";
export const constantRouterMap = ${constant};`;
    await fse.outputFileSync(dir, str, "utf8");
    resolve();
  });
};

const joinFiltersToProject = (comm, projectCode) => {
  return new Promise(async (resolve) => {
    const url = path.resolve(
      __dirname,
      "../../projects/" + projectCode + "/src/filters/config.js"
    );

    let filtes = fse.readFileSync(url, "utf8");
    filtes = filtes
      .replace("export default ", "")
      .replace(/\s/g, "")
      .replace(/([a-zA-Z0-9-_]+):/g, '"$1":')
      .replace(",};", "}");
    filtes = JSON.parse(filtes);

    if (comm.options && comm.options.indexOf("Filters.list") > -1) {
      const key = comm.options
        .replace(/Filters\.list\(/g, "")
        .replace(/\)/g, "");
      const i = Object.keys(filtes).findIndex((a) => a === key);

      if (i === -1) {
        filtes = Object.assign({}, filtes, comm.filterObj);
        fse.outputFileSync(
          url,
          `export default ${JSON.stringify(filtes)}`,
          "utf8"
        );
        delete comm.filterObj;
      } else {
        let o = Object.keys(filtes).find((a) => a === key);
        if (!o) return;
        if (JSON.stringify(filtes[o]) !== JSON.stringify(comm.filterObj)) {
          filtes = Object.assign({}, filtes, comm.filterObj);
          delete comm.filterObj;
          fse.outputFileSync(
            url,
            `export default ${JSON.stringify(filtes)}`,
            "utf8"
          );
        }
      }
    }

    resolve();
  });
};

const executeEventsEmits = async (strcomm) => {
  if (Array.isArray(strcomm) && strcomm.length > 0) {
    const fraw = {
      form: (as, nm) => {
        let index = -1;
        if (as.assign) {
          index = strcomm.findIndex((a) => a.comm.index === as.assign);
          if (index < 0) return "";
          let asr = {
            Form__Search: `
          const Pcf = Object.values(pageConfig.value).flat();
          let Ci = -1;
          if (comm.assign) {
            Ci = Pcf.findIndex((a) => a.index === comm.assign);
          }
          if (Ci > -1) {
            compId.value[Ci]?.fetchData();
          }`,
          };

          return {
            asr: asr[nm] || "",
            fns: "",
          };
        } else {
          const fn = toHump(as.apiUrl);
          let asr = {
            Form__Search: `fetch${fn}(val)`,
          };
          return {
            asr: asr[nm] || "",
            fns: "",
          };
        }
      },
      table: (as, nm, comm) => {
        const index = strcomm.findIndex((a) => a.componentKey === "table");
        if (index < 0) return "";
        let asr = {
          Table_Modal__Open: `
          modal.apiType = btnInfo.key;
          Open_Modal(comm.index);`,
          Table_Modal__Close: `
          Close_Modal(comm.index);
          `,
          Table_Operate__Change: `
          modal.apiType = btnInfo.key;
          if (btnInfo.key === "delete") {
            confirmDelete(comm, btnInfo, row);
          } else {
            Open_Modal(comm.index);
            const val = getTableRowValue(comm, btnInfo, row);
            nextTick(() => {
              modalRef.value?.setForm(val);
            });
          }`,
        };
        let fns = ``;
        return {
          asr: asr[nm] || "",
          fns: fns,
        };
      },
      list: (as, nm, comm, args) => {
        let asr = {
          List_Onload: `if (item2.index === comm.index) {
    fetch${toHump(as.apiUrl)}(${args});
  }`,
        };
        return {
          asr: asr[nm] || "",
          fns: "",
        };
      },
    };
    let cn = [];
    let fn = [];
    strcomm.map((a) => {
      const reg = new RegExp(
        /emit\(["']([a-zA-Z0-9_-]+)["'](\,\s?([a-zA-Z0-9_-\s,]+))?\)/g
      );
      a.commstr.replace(reg, (str, $1, $2, $3) => {
        console.log(a.componentKey, ".componentKey");
        let ex = "";
        if (fraw[a.componentKey]) {
          let args = `${$3}`;
          let s3 = $3 ? `${$3}` : "";
          const bn = fraw[a.componentKey](a.comm, $1, a.comm, s3);
          if (bn && bn.asr) {
            ex = bn.asr;
            // let ae = bn.match(/\([a-zA-Z0-9_-]+\)/g);

            let an = `@${$1}="(${s3}) => { ${$1}(${args || ""}) }"`;
            if (bn.fns && !fn.includes(bn.fns)) {
              fn.push(bn.fns);
            }
            if (!cn.includes(an)) {
              cn.push(an);
              fn.push(`const ${$1} = (${args || ""}) => { ${ex} }`);
            } else {
              const idx = fn.findIndex(
                (a) => a.indexOf(`const ${$1} = (${args || ""})`) > -1
              );
              if (idx > -1) {
                fn[idx] = fn[idx].replace(/{(\s?\n?(.*?)\s?\n?)}/g, `$1${ex}`);
              }
            }
          }
        }
      });
    });
    return {
      cn,
      fn,
    };
  } else {
    return [];
  }
};

const executeModel = async (strcomms) => {
  if (
    strcomms.some(
      (a) => a.comm.componentKey === "modal" || a.comm.componentKey === "table"
    )
  ) {
    let str = `const Open_Modal = (index) => {
  currentIndex.value = index;
  modalRef.value?.showModal();
};

const Close_Modal = () => {
  modalRef.value?.resetFields();
  modalRef.value?.close();
};
const Confirm_Modal = async (val) => {
  const type = modal.apiType;
  const vals = Object.assign({}, val, modal.value.row);
  fetchTableApi(type, vals, modal.value.index);
};`;
    return str;
  } else {
    return "";
  }
};

const executeApi = async (strcomms, _modals) => {
  const apiUrls = new Set();
  const methods = new Set();
  const executes = new Set();
  const emits = await executeEventsEmits(strcomms);
  console.log(emits, "emits");
  const excuteCommApi = {};
  let comms = [];
  let allComms = [];
  const promises = strcomms.map(async (strcomm) => {
    try {
      let a = { ...strcomm.comm, ...strcomm.comm.attrs };

      if (a.options && a.options.indexOf("Filters") === -1) {
        a.apiUrl = a.options;
      }

      if (!a.apiUrl) {
        if (a.index && a.index.split("-").length < 3) {
          comms.push(a);
        }
        return;
      }

      if (a.componentKey === "table" && a.data && typeof a.data === "string") {
        a.apiUrl = a.data;
        delete a.data;
      }
      const apis = a.apiUrl.split("|");
      let i = 0;
      await dep(apis, async (apiUrl) => {
        apiUrl = apiUrl.split(":");
        apiUrl = apiUrl[0];
        const fn = toHump(apiUrl);

        const importStatement = `import { ${fn} } from "@/apis${apiUrl}";`;
        if (
          a.componentKey === "list" ||
          a.componentKey === "banner" ||
          a.componentKey === "form"
        ) {
          const args = {
            list: "page",
            form: "val",
          };
          const vars = a.pageSize
            ? `list.value["${a.index}"].concat(data.list || data || [])`
            : `data.list || data || []`;
          const estr = {
            list: `if (!list.value["${a.index}"]) list.value["${a.index}"] = [];
                  list.value["${a.index}"] = ${vars};`,
            banner: `if (!list.value["${a.index}"]) list.value["${a.index}"] = [];
                  list.value["${a.index}"] = ${vars};`,
            form: `message.success("操作成功！")`,
          };
          const params = a.pageSize
            ? `{ page: page || 1, limit: ${a.pageSize || 10}, {...${args[a.componentKey]}.formData}}`
            : `{...${args[a.componentKey]}.formData}`;
          const fetchFunction = `
          const fetch${fn} = async (${args[a.componentKey] || ""}) => {
            try {
              const { code, data } = await ${fn}(Object.assign({}, ${params}));
              if (code === rescf.codeVal) {
                ${estr[a.componentKey] || ""}
              }
            } catch (error) {
              console.error('Error fetching data:', error);
            }
          };
        `;

          const executeCall = `fetch${fn}();`;

          apiUrls.add(importStatement);
          methods.add(fetchFunction);
          if (a.componentKey !== "form") {
            executes.add(executeCall);
          }
        } else if (a.componentKey === "table") {
          if (!excuteCommApi[a.index]) excuteCommApi[a.index] = {};
          const gs = {
            0: "apiGet",
            1: "apiPost",
            2: "apiPut",
            3: "apiDelete",
          };
          excuteCommApi[a.index][toHump(`${gs[i]}/` + fn)] = fn;
          const modal = _modals.find((m) => m.index === a.index);
          const confirmDelete = a.btns.includes("delete")
            ? `const confirmDelete = (comm, btnInfo, row) => {
            const val = getTableRowValue(comm, btnInfo, row);
            Modal.confirm({
                title: "提示",
                content: "确定删除吗？",
                onOk() {
                  fetchTableApi("delete", val, comm.index);
                },
                onCancel() {},
              });
          };`
            : "";
          const mf = a.btns.every((value) =>
            ["add", "edit", "delete", "view"].includes(value)
          )
            ? `const getTableRowValue = (comm, btnInfo, row) => {
                if (btnInfo.key === "add") return {};
                const val = { ...row };
                const modal = modals.value.find((a) => a.index === comm.index);
                Object.keys(val).forEach((key) => {
                  const attr = modal.attrs.find((a) => a.field === key);
                  if (attr && attr.arr2str && val[key]) {
                    val[key] = val[key].split(",");
                  }
                });
                modal.row = val;
                return val;
              };`
            : "";
          const fetchFunction = `${confirmDelete}${mf}const getTableApis = (comm, gs) => {
            const type = gs.substr(0, 1).toUpperCase() + gs.substr(1);
            const fn = Object.keys(comm).find((a) => a.indexOf(type) > -1);
            const nm = fn.substr(0, 1).toUpperCase() + fn.substr(1);
            return comm["api" + nm];
          };
          const fetchTableApi = async (gs, val, index) => {
            const Pcf = Object.values(pageConfig.value).flat(); 
            const Cp = Pcf.find((a) => a.index === index);
            const Api = getTableApis(Cp, gs);
            const { code, msg } = await Api(val);
            if (code === rescf.codeVal) {
              commId.value?.[Ci].fetchData();
              Close_Modal();
            } else {
              message.error(msg);
            }
            execApi()
          };
          `;
          a = Object.assign({}, a, excuteCommApi[a.index], {
            modalTitle: modal.title || "",
          });
          methods.add(fetchFunction);
          apiUrls.add(importStatement);
        } else {
          if (!excuteCommApi[a.index]) excuteCommApi[a.index] = {};
          excuteCommApi[a.index][toHump(fn)] = fn;
          a = Object.assign({}, a, excuteCommApi[a.index]);
          apiUrls.add(importStatement);
        }
        i++;

        if (a.index && a.index.split("-").length < 3) {
          const ci = comms.findIndex((b) => b.index === a.index);
          if (ci > -1) {
            comms[ci] = a;
            allComms[ci] = a;
          } else {
            comms.push(a);
            allComms.push(a);
          }
        } else {
          const ci = comms.findIndex((b) => b.index === a.index);
          if (ci > -1) {
            allComms[ci] = a;
          } else {
            allComms.push(a);
          }
        }
        return a;
      });
    } catch (error) {
      console.error("Error processing component:", error);
    }
  });

  const p = await Promise.all(promises);
  const modals = await executeModel(strcomms);
  return {
    comms,
    allComms,
    excuteCommApi: excuteCommApi,
    apiUrls: Array.from(apiUrls),
    methods: Array.from(methods),
    executes: Array.from(executes),
    modals,
    emits: emits,
  };
};

const canJoinRouter = (project) => {
  return project.template === 2;
};
const writeFile = async (id, project, url, components, modals, name, grids) => {
  return new Promise(async (resolve) => {
    const comms = [...components];
    if (canJoinRouter(project)) {
      await joinRoutersToProject(id, project.code, url, name); // 生成路由
    }
    let strcomm = [];
    await dep(comms, async (comm) => {
      comm = Object.assign({}, comm, comm.attrs);
      const code = comm.componentKey;
      const c = await Components.findOne({ code: code });
      if (comm && comm.componentKey === "table") {
        Object.keys(comm).map((key) => {
          const validKeyPattern = /^[\w-]+-(\w+)$/;
          if (
            key.match(validKeyPattern) &&
            !Object.keys(comm._esr).includes(key)
          ) {
            delete comm[key];
          }
        });
      }
      delete comm.attrs;
      delete comm._esr;

      await joinPackagejson(c.content, project.code); // 加入到package.json
      await joinApisToProject(project.code, comm); // 生成apis
      strcomm = strcomm.concat({
        comm,
        apiUrl:
          comm.apiUrl ||
          (comm.options && comm.options.indexOf("Filters") === -1
            ? comm.options
            : null),
        componentKey: code,
        commstr: await joinComponentsToProject(c.content, project.code, code),
      }); // 组件加入到项目
      await joinFiltersToProject(comm, project.code, code);
    });
    const executes = await executeApi(strcomm, modals);

    console.log(executes.comms, "strcomm");

    modals = modals.map((a) => {
      delete a.show;
      return a;
    });

    await joinViewsToProject(
      id,
      project.code,
      executes,
      modals,
      strcomm,
      url,
      grids
    ); // 页面加入到项目
    resolve(executes.comms);
  });
};

const prettierFile = async (project) => {
  const dir = path.resolve(__dirname, "../../projects/" + project.code);
  shell.cd(dir);
  stdout = await shell.exec(
    `prettier --write "${dir}/src/**/*.{js,jsx,ts,tsx,vue,scss,css}"`
  );
  stdout = await shell.exec(`prettier --write "${dir}/package.json"`);
};

class PageCtl {
  async get(ctx) {
    let limit = ctx.query.limit ? ctx.query.limit : 10;
    let page = ctx.query.page ? ctx.query.page : 1;

    let where = {};
    const filters = ["name", "project"];
    filters.forEach((key) => {
      if (ctx.query[key]) {
        if (key === "name") {
          where[key] = new RegExp(ctx.query[key]);
        } else {
          where[key] = ctx.query[key];
        }
      }
    });

    let _Page = await Page.find(where);
    limit = parseInt(limit);
    let skip = limit * (parseInt(page) - 1);
    let total = _Page.length;
    let list = [];

    if (total > 0) {
      list = await Page.find(where)
        .populate("project")
        .limit(limit)
        .skip(skip)
        .sort({ _id: -1 });
    }

    ctx.body = {
      code: 200,
      msg: "success",
      data: {
        limit: limit,
        page: page,
        list: list,
        total: total,
      },
    };
  }

  async all(ctx) {
    let _Page = await Page.find({});
    ctx.body = {
      code: 200,
      msg: "success",
      data: _Page,
    };
  }

  async create(ctx) {
    const name = ctx.request.body.name;
    const project = ctx.request.body.project;
    const url = ctx.request.body.url;
    const exit = await Page.findOne({
      name: name,
    });
    if (exit) {
      ctx.body = {
        errCode: -1,
        msg: "页面已存在",
      };
      return;
    }

    const _Page = await new Page({
      name,
      project,
      url,
      createAt: new Date(),
      updateAt: new Date(),
    }).save();

    ctx.body = {
      code: 200,
      msg: "success",
      data: _Page,
    };
  }

  async modify(ctx) {
    const _id = ctx.request.body._id;
    const name = ctx.request.body.name;
    const project = ctx.request.body.project;
    const url = ctx.request.body.url;
    const components = ctx.request.body.components || [];
    const exit = await Page.findOne({
      $or: [{ name: name }],
      _id: { $ne: _id },
    });
    if (exit) {
      ctx.body = {
        code: -1,
        msg: "页面已存在",
      };
      return;
    }

    const _Page = await Page.updateOne(
      { _id: _id },
      {
        name,
        project,
        url,
        components,
        updateAt: new Date(),
      }
    );

    ctx.body = {
      code: 200,
      msg: "success",
      data: _Page,
    };
  }

  async setOff(ctx) {
    const id = ctx.request.body.id;
    const components = ctx.request.body.components;
    const modals = ctx.request.body.modals;
    const project = ctx.request.body.project;
    const url = ctx.request.body.url;
    const name = ctx.request.body.name;
    const grids = ctx.request.body.grids;

    let _Page = await Page.findOne({ _id: id });

    const comms = await writeFile(
      id,
      project,
      url,
      components,
      modals,
      name,
      grids
    );
    _Page = await Page.updateOne(
      { _id: id },
      {
        name,
        project,
        url,
        components: comms,
        modals,
        grids,
        updateAt: new Date(),
      }
    );

    ctx.body = {
      code: 200,
      msg: "success",
      data: _Page,
    };
    prettierFile(project);
  }

  async info(ctx) {
    const id = ctx.query.id;
    const _Page = await Page.findOne({
      _id: id,
    }).populate("project");
    ctx.body = {
      code: 200,
      msg: "success",
      data: _Page,
    };
  }
  async remove(ctx) {
    const id = ctx.params.id;
    await Page.deleteOne({
      _id: id,
    });

    ctx.body = {
      code: 200,
      msg: "success",
    };
  }
}

module.exports = new PageCtl();
